package com.yayo.mangement.task;

import com.yayo.mangement.authentication.annotations.ExcelProperty;
import com.yayo.mangement.authentication.enums.SuffixEnum;
import com.yayo.mangement.resp.WorkbookResp;
import com.yayo.mangement.utils.ExcelUtils;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class ExportTask {

    private String title;

    /**
     * 导出excel方法，以后此方法应改为继承接口，由接口调用这里，实现类可添加docx导入导出和其他格式导入导出
     *
     * @param exportList
     * @param clazz
     * @return WorkbookResp
     * @throws IntrospectionException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public WorkbookResp xlsxExportTask(List<Object> exportList, Class<?> clazz) throws IntrospectionException, InvocationTargetException, IllegalAccessException, ExecutionException, InterruptedException {
        //构建文档内容
//        XSSFWorkbook xssfWorkbook = this.buildContent(exportList, clazz);
        //生成xssf文档实例
        XSSFWorkbook xssfWorkbook = ExcelUtils.exportExcel(exportList, clazz);

        return WorkbookResp.builder()
                .workbook(xssfWorkbook)
                .fileName(this.getFileName(SuffixEnum.EXCEL))
                .build();
    }


    /**
     * 构建内容数组，支持多线程并发处理
     *
     * @param exportList 导出列表
     * @param clazz      实体类类型
     * @return 二维字符串数组，表示表格内容
     * @throws ExecutionException        执行异常
     * @throws InterruptedException      中断异常
     * @throws IntrospectionException    反射异常
     * @throws InvocationTargetException 方法调用异常
     * @throws IllegalAccessException    非法访问异常
     */
    public XSSFWorkbook buildContent(List<Object> exportList, Class<?> clazz) throws  IntrospectionException, InvocationTargetException, IllegalAccessException {
        Field[] fieldArr = clazz.getDeclaredFields();
        String totalTitle = clazz.getAnnotation(ExcelProperty.class) == null ? null : clazz.getAnnotation(ExcelProperty.class).value();
        this.title = totalTitle == null ? "" : totalTitle;
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet();
        int startRow = 0;
        if(totalTitle != null){
            XSSFRow titleRow = sheet.createRow(startRow);
            CellRangeAddress cellRangeAddress = new CellRangeAddress(0,0,0,fieldArr.length-1);
            sheet.addMergedRegion(cellRangeAddress);
            XSSFCell cell = titleRow.createCell(0);
            cell.setCellValue(this.title);
            startRow ++;
        }
        XSSFRow row = sheet.createRow(startRow);
        // 列号，这个数组按照列进行依次插入，列号依次递增不再归零，所以放在最外层
        int column = 0;
        // 遍历获取的实体类列数组
        for (Field field : fieldArr) {
            // 判断是否有ExcelProperty注解，如果没有则跳过不处理
            if (field.isAnnotationPresent(ExcelProperty.class)) {
                // 根据注解获取value值，此处注解的value为要生成文档的列标题
                String title = field.getAnnotation(ExcelProperty.class).value();
                // 如果标题为空值（不包含空格），则使用属性名作为标题
                if (title == null || "".equals(title)) {
                    title = field.getName();
                }
                // 存入标题
                XSSFCell cell = row.createCell(column);
                cell.setCellValue(title == null ? "" : title);
                // 循环完成，第一列插入完毕，列号增加到下一列
                column++;
            }
        }
        startRow ++;
        // 提交任务
        AtomicInteger nextRowIndex = new AtomicInteger(startRow);
        for (int i = 0; i < exportList.size(); i++) {
            Object obj = exportList.get(i);
            processRow(obj, clazz, sheet ,nextRowIndex, fieldArr);
        }
        return workbook;
    }

    /**
     * 处理单个对象的一行数据
     *
     * @param obj      当前对象
     * @param clazz    类型
     * @param nextRowIndex  内容数组
     * @param fieldArr 字段数组
     * @throws IntrospectionException    反射异常
     * @throws InvocationTargetException 方法调用异常
     * @throws IllegalAccessException    非法访问异常
     */
    private void processRow(Object obj, Class<?> clazz, XSSFSheet sheet, AtomicInteger nextRowIndex, Field[] fieldArr) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        // 列号，每一行内容循环完毕后，列号应该归零，行号加一再次存入
        int columnIndex = 0;
        int maxSize = 0;
        XSSFRow row = sheet.createRow(nextRowIndex.get());
        //计算要合并的行数
        for (Field field : fieldArr) {
            if (field.isAnnotationPresent(ExcelProperty.class)) {
                ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
                boolean isMergeRow = annotation.mergeRow();
                if(isMergeRow){
                    if(field != null){
                        PropertyDescriptor keyPd = new PropertyDescriptor(field.getName(), clazz);
                        // 获取读方法，即属性的get方法
                        Method keyGetMethod = keyPd.getReadMethod();
                        int size = keyGetMethod.invoke(obj) instanceof List ? ((List<?>) keyGetMethod.invoke(obj)).size(): 0;
                        if(size > maxSize){
                            maxSize = size ;
                        }
                    }
                }
            }
        }
        // 遍历获取的实体类列数组
        for (Field field : fieldArr) {
            // 判断是否有ExcelProperty注解，如果没有则跳过不处理
            if (field.isAnnotationPresent(ExcelProperty.class)) {
                // 根据属性名获取该属性的所有描述
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                // 获取读方法，即属性的get方法
                Method getMethod = pd.getReadMethod();
                //创建DataContent实例
                ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
                boolean isMergeRow = annotation.mergeRow();
                if(maxSize > 1 && !isMergeRow){
                    CellRangeAddress cellRangeAddress = new CellRangeAddress(nextRowIndex.get(),
                            nextRowIndex.get() + maxSize -1, columnIndex, columnIndex);
                    sheet.addMergedRegion(cellRangeAddress);
                }
                if(isMergeRow){
                    List<Object> list = (List<Object>) getMethod.invoke(obj) ;
                    if(!CollectionUtils.isEmpty(list)){
                        for(int k = 0 ; k < list.size() ; k ++){
                            XSSFRow listRow = sheet.getRow(nextRowIndex.get() + k);
                            if(listRow == null){
                                listRow = sheet.createRow(nextRowIndex.get() + k);
                            }
                            XSSFCell cell = listRow.createCell(columnIndex);
                            //向单元格中存值
                            cell.setCellValue(list.get(k) + "");
                            //设置单元格样式
//                        cell.setCellStyle(style);
                        }
                    }
                }else {
                    String columnValue = getMethod.invoke(obj) == null ? "": getMethod.invoke(obj).toString();
                    XSSFCell cell = row.createCell(columnIndex);
                    cell.setCellValue(columnValue);
                }
                columnIndex++;
            }
        }
        nextRowIndex.addAndGet(maxSize);
    }


    /**
     * 生成时间戳文件名
     *
     * @return
     */
    private String getFileName(SuffixEnum suffixEnum) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String datetimeName = title + "_" + sdf.format(new Date());
        return datetimeName + "." + suffixEnum.getCode();
    }
}
